var rss = require('./lib/rss.js'),
    api = require('./lib/api.js'),
    fs = require('path'),
    io = require('fs');
    
if (!fs.existsSync('app.cnf')) {
    console.error("[%s]: app.cnf was not found", timestamp());
    process.exit(1);
}

console.info("[%s]: parsing configuration file", timestamp());

io.readFile('app.cnf', function (error, config) {
    if (error) {
        console.error(error);
        process.exit(1);
    }
    
    config = JSON.parse(config);
    
    // We defer monitorElections because we need to
    // make sure that we have the list of sites first
    monitorSites(config, monitorElections);
    monitorBadges(config);
});

var sites = {},
    host = /^(http:\/\/[^\/]+)\//;

function monitorSites(config, callback) {
    console.info("[%s]: setting up sites api monitor", timestamp());

    if (!config.sites.file || !config.sites.api || !config.sites.interval) {
        console.error("[%s]: sites.file, sites.api, or sites.interval is undefined",
            timestamp());
        process.exit(1);
    }
    
    var monitor = Object.create(api).constructor(
        config.sites.api,
        {
            autopage: true,
            key: config.apikey
        }
    );
    
    monitor.on('error', onerror);
    monitor.on('complete', function monitor(items) {
        console.log("[%s]: polled for site list, %d sites returned",
            timestamp(), items.length);
    
        var changed = false;
    
        items && items.forEach(function (site) {
            if (site.site_type === "main_site") {
                if (!sites[site.site_url]) {
                    sites[site.site_url] = {
                        'favicon': site.favicon_url,
                        'icon': site.icon_url,
                        'name': site.name,
                        'elections': []
                    };
                    
                    changed = true;
                }
            }
        });
        
        if (changed) {
            console.log("[%s]: saving site list to file", timestamp());
            io.writeFile(config.sites.file, JSON.stringify(sites), onerror);
        }
    });
    
    if (fs.existsSync(config.sites.file)) {
        console.info("[%s]: reading sites information from file", timestamp());
    
        io.readFile(config.sites.file, function readFile(error, content) {
            if (error) {
                console.error(error);
                process.exit(1);
            }
            
            if (content) {
                sites = JSON.parse(content);
            }
            
            if (typeof callback === 'function') {
                callback(config);
            }
            
            console.info("[%s]: starting sites api polling (deferred)",
                timestamp());
            monitor.every(config.sites.interval * 1000, false);
        });
    } else {
        if (typeof callback === 'function') {
            monitor.once('complete', function once() {
                callback(config);
            });
        }
        
        console.info("[%s]: starting sites api polling", timestamp());
        monitor.every(config.sites.interval * 1000);
    }
}

function monitorBadges(config) {
    console.info("[%s]: setting up badge api monitor", timestamp());
    
    if (!config.badges.file || !config.badges.api || !config.badges.interval) {
        console.error("[%s]: badges.file, badges.api, or badges.interval is undefined",
            timestamp());
    }
    
    var monitor = Object.create(api).constructor(
        config.badges.api,
        {
            autopage: true,
            key: config.apikey
        }
    );
    
    monitor.on('error', onerror);
    monitor.on('complete', function monitor(badges) {
        console.info("[%s]: polled for badges, %d badges returned",
            timestamp(), badges.length);
        
        // We should use a filter for this instead,
        // but this is a bit easier for the moment...
        badges.forEach(function (badge) {
            delete badge.badge_id;
            delete badge.award_count;
            delete badge.badge_type;
            delete badge.link;
        });
        
        console.info("[%s]: saving badges to file", timestamp());
        io.writeFile(config.badges.file, "var badgeInfo = " + JSON.stringify(badges) + ";", onerror);
    });
    
    console.info("[%s]: starting badges api polling", timestamp());
    monitor.every(config.badges.interval * 1000);
}

function monitorElections(config) {
    console.info("[%s]: setting up election feed monitor",
        timestamp());

    if (!config.elections.users || !config.elections.feed ||
            !config.elections.interval || !config.elections.keyword) {
        console.error("[%s]: elections.users, elections.feed, or elections.interval is undefined",
            timestamp());
        process.exit(1);
    }

    var update = 0;
    
    Object.keys(sites).forEach(function (site) {
        if (sites[site].elections.length) {
            update = Math.max(update, Math.max.apply(null, sites[site].elections));
        }
    });
    
    var monitor = Object.create(rss).constructor(
        config.elections.feed,
        update
    );
    
    monitor.on('error', onerror);
    monitor.on('complete', function monitor(entries) {
        console.info("[%s]: polled for rss items, found %d candidates",
            timestamp(), entries.length);
    
        var changed = false;
    
        entries.forEach(function (entry) {
            var site = entry.link.match(host)[1].replace('meta.', ''),
                ignore = true;
            
            if (Array.isArray(config.elections.users)) {
                ignore = config.elections.users.indexOf(entry.author.name) === -1;
            } else {
                ignore = config.elections.users !== entry.author.name;
            }
            
            ignore = ignore || entry.title.indexOf(config.elections.keyword) === -1;
            
            if (!ignore) {
                var last = 0;
                
                if (sites[site].elections.length) {
                    last = Math.max.apply(null, sites[site].elections);
                }

                if (entry.posted > last) {
                    sites[site].elections.unshift(entry.posted);
                    changed = true;
                    
                    console.info("[%s]: adding new election for %s, started %s",
                        timestamp(), site, timestamp(new Date(entry.posted)));
                }
            }
        });
        
        if (changed) {
            console.log("[%s]: saving site list to file", timestamp());
            io.writeFile(config.sites.file, JSON.stringify(sites), onerror);
        }
    });
    
    console.info("[%s]: starting election feed polling", timestamp());
    monitor.every(config.elections.interval * 1000);
}

function timestamp(date) {
    date = date || new Date();
    
    return date.getUTCFullYear() +
        "-" + zeros(date.getUTCMonth() + 1) +
        "-" + zeros(date.getUTCDate()) + 
        " " + zeros(date.getUTCHours()) +
        ":" + zeros(date.getUTCMinutes()) +
        ":" + zeros(date.getUTCSeconds());
}

function zeros(number) {
    return number < 10 ? '0' + number : number;
}

function onerror(error) {
    if (error) {
        console.error("[%s]: " + error, timestamp());
        console.trace();
        process.exit(1);
    }
}